/******************************************************************************

	COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2009, 2010.

	This file is part of Maxsi Engine.

	Maxsi Engine is free software: you can redistribute it and/or modify it
	under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or (at your
	option) any later version.

	Maxsi Engine is distributed in the hope that it will be useful, but WITHOUT
	ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
	FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
	for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with Maxsi Engine. If not, see <http://www.gnu.org/licenses/>.

	MaxsiEngine.dll
	A general purpose C++ library for the Maxsi Technology Project.

	MaxsiBuffer.h
	A flexible buffer class.

****************************************************************************/

#ifndef MaxsiBuffer_H
#define MaxsiBuffer_H

BeginMaxsiNamespace

//=============================================================================
//	Declare the access rights to a given Maxsi Buffer.
//=============================================================================

//=============================================================================
//	MAXSI_BUFFER_FLAG_WRITE - Thread may write to the bufffer.
//=============================================================================
#define	MAXSI_BUFFER_FLAG_WRITE		(0x0000001)

//=============================================================================
//	MAXSI_BUFFER_FLAG_READ - Thread may read from the buffer.
//=============================================================================
#define	MAXSI_BUFFER_FLAG_READ		(0x0000002)	

//=============================================================================
//	MAXSI_BUFFER_FLAG_POINTER - Thread may access the buffer pointer and modify
//	the buffer, the buffer may not change size when this is set.
//=============================================================================
#define	MAXSI_BUFFER_FLAG_POINTER	(0x0000004)	

//=============================================================================
//	MAXSI_BUFFER_FLAG_POINTER - The buffer contains private data and should be
//	reset as soon as possible.
//=============================================================================
#define	MAXSI_BUFFER_FLAG_SECURE	(0x0000008)

//=============================================================================
//	MAXSI_BUFFER_FLAG_INUSE - The buffer is currently in async use, writing is
//	not allowed at this time.
//=============================================================================
#define	MAXSI_BUFFER_FLAG_INUSE		(0x0000010)	

//=============================================================================
//	MAXSI_BUFFER_FLAG_DEFAULT - The default flag for using a buffer. To do
//	anything you must specify something else than this.
//=============================================================================
#define	MAXSI_BUFFER_FLAG_DEFAULT	(0x0000000)

//=============================================================================
//	MAXSI_BUFFER_FLAG_ALL_RIGHTS - Gives you all rights to modify the buffer.
//=============================================================================
#define	MAXSI_BUFFER_FLAG_ALL_RIGHTS (MAXSI_BUFFER_FLAG_WRITE | MAXSI_BUFFER_FLAG_READ | MAXSI_BUFFER_FLAG_POINTER)

//=============================================================================
//	Useful debugging macros.
//=============================================================================
#ifdef _DEBUG
#define MAXSI_BUFFER_LOCK_PARAMS MAXSI_BUFFER_FLAG_ALL_RIGHTS, __FUNCTION__, __LINE__
#define MAXSI_BUFFER_LOCK_PARAMSEX , __FUNCTION__, __LINE__
#define MAXSI_BUFFER_LOCK_EX(Parameter) Lock(Parameter MAXSI_BUFFER_LOCK_PARAMSEX)
#else
#define MAXSI_BUFFER_LOCK_PARAMS
#define MAXSI_BUFFER_LOCK_PARAMSEX
#define MAXSI_BUFFER_LOCK_EX(Parameter) Lock(Parameter MAXSI_BUFFER_LOCK_PARAMSEX)
#endif

//=============================================================================
//	MaxsiBuffer - A smart system to store a changing buffer in for async
//	reading and writing in multithreaded designs.
//=============================================================================
CLASSLINK MaxsiBuffer
{
public:
	MaxsiBuffer();
	~MaxsiBuffer();

public:
	BYTE*					Buffer;
	size_t					BufferSize;
	size_t					BufferUsed;
	size_t					BufferOffset;
	size_t					BufferIdealSize;

#ifdef _DEBUG
public:
	char*					DebugCaller;
	size_t					DebugLine;
#endif

protected:
	MaxsiHandle				BufferLock;

public:
	FLAGSL32				GetBufferFlags();

private:
	FLAGSL32				SetBufferFlags(FLAGSL32 NewFlags);
	FLAGSL32				BufferFlags;

public:

	MaxsiError Lock(FLAGSL32 Flags = MAXSI_BUFFER_FLAG_ALL_RIGHTS
#ifdef _DEBUG
, char* Caller = NULL, size_t Line = 0
#endif
	);
	MaxsiError			Unlock();

	MaxsiError			Write(MaxsiBuffer* Input, size_t Size);
	MaxsiError			Write(BYTE* Input, size_t Size);
	MaxsiError			Read(BYTE* Dest, size_t Size);

	BYTE*		GetBuffer();			// The real buffer
	BYTE*		GetPointer();			// The current position of the next byte in the buffer
	size_t		GetBufferSize();
	size_t		GetBufferUsed();
	size_t		GetBufferAvailable();
	size_t		GetBufferOffset();
	size_t		GetPointerSizeFollowingData();
	MaxsiError			SetBufferSize(size_t Size, bool Force = false);
	MaxsiError			SetBufferOffset(size_t Offset);
	MaxsiError			SetBufferUsed(size_t Used);
	BYTE*		ProgressPointer(BYTE* Position, size_t Size); // Progresses the pointer provided Size bytes and returns the result if the pointer given is points to somewhere inside the real buffer
	MaxsiError			ProgressBuffer(size_t Size, bool Force = false); // Progresses the buffer Size bytes forward and returns an error if it goes beyond the size of the buffer

	MaxsiError			Clear(); // Marks all data in the buffer as read and resets the pointer to the first byte in the buffer
	MaxsiError			MarkDataAsRead(BYTE* Pointer, size_t Size);

	MaxsiError			SetInUse();
	MaxsiError			ClearInUse();
	bool				IsInUse();
	MaxsiError			MayWrite();
	MaxsiError			MayRead();

	bool		ShouldDoEvenSillierDebugStuff;

};

//=============================================================================
//	Redirect functions depending on what kind of string system we use.
//=============================================================================
#ifdef ME_USE_MULTIBYTE_STRING

	#define FindStringInBufferM FindStringInBufferW

#else

	#define FindStringInBufferM FindStringInBufferA

#endif

//=============================================================================
//	MaxsiBuffer* CreateBuffer(size_t Size, FLAGSL8 Flags =
//	ME_Buffer_Flag_Default);
//
//	Creates a new buffer able to hold Size bytes. Returns NULL upon failure,
//	otherwise it returns the new buffer.
//=============================================================================
LINK MaxsiBuffer* CreateBuffer(size_t Size, FLAGSL32 Flags = MAXSI_BUFFER_FLAG_DEFAULT);

//=============================================================================
//	bool DeleteBuffer(MaxsiBuffer* Buffer);
//
//	Deletes a buffer previously allocated using CreateBuffer().
//=============================================================================
LINK bool DeleteBuffer(MaxsiBuffer* Buffer);

//=============================================================================
//	size_t FindStringInBufferM(MaxsiBuffer* Buffer, MESTR* String);
//
//	Returns how long it had to search into Buffer to find String, or SIZE_MAX
//	if String was not found in Buffer.
//=============================================================================
LINK size_t FindStringInBufferA(MaxsiBuffer* Buffer, char* String);
LINK size_t FindStringInBufferW(MaxsiBuffer* Buffer, wchar_t* String);

//=============================================================================
//	size_t FindStringInBufferEx(MaxsiBuffer* Buffer, BYTE* Buffer2,
//	size_t Buffer2Len);
//
//	Searches for Buffer2 inside Buffer and returns how long it had to search
//	into buffer to find Buffer2. Buffer2Len is the size of Buffer2. Returns
//	NULL if Buffer2 was not found inside Buffer.
//=============================================================================
LINK size_t FindStringInBufferEx(MaxsiBuffer* Buffer, BYTE* Buffer2, size_t Buffer2Len);

EndMaxsiNamespace

#endif
